package com.fenghuajueli.libbasecoreui.upload

import android.app.Application
import android.content.Context
import android.os.Build
import com.blankj.utilcode.util.DeviceUtils
import com.blankj.utilcode.util.LogUtils
import com.fenghuajueli.lib_net.LoggingInterceptor
import com.fenghuajueli.libbasecoreui.BaseApplication
import com.fenghuajueli.libbasecoreui.constants.AppConfigInfo
import com.fenghuajueli.libbasecoreui.user.UserInfoUtils
import com.fenghuajueli.libbasecoreui.utils.MmkvUtils
import com.umeng.analytics.pro.ba
import com.umeng.commonsdk.UMConfigure
import com.umeng.commonsdk.listener.OnGetOaidListener
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import okhttp3.OkHttpClient
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.text.SimpleDateFormat
import java.time.Duration
import java.time.LocalDate
import java.time.temporal.ChronoUnit
import java.util.*
import java.util.concurrent.TimeUnit
import kotlin.math.pow
import kotlin.math.sqrt


abstract class BaseUpload {

    companion object {
        val appScope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
    }

    private val baseUrl = "http://${AppConfigInfo.HTTP_HOST}/api/v1/public/"
    private lateinit var uploadService: UploadService

    internal val FIRST_LAUNCH = "FIRST_LAUNCH"

    internal val format = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())

    internal var oaid: String? = ""

    init {
        initUploadLocalService()
    }

    /**
     * 获取OAID
     *
     * @param application
     * @param onGetOaidListener
     */
    fun initOaidAction(application: Application, onGetOaidListener: OnGetOaidListener?) {
        try {
            UMConfigure.getOaid(application) {
                oaid = it
                onGetOaidListener?.onGetOaid(it)
            }
        } catch (e: Exception) {
            onGetOaidListener?.onGetOaid("")
            e.printStackTrace()
        }
    }

    internal suspend fun action(channel: Channel, block: suspend () -> Unit) {
        when (channel) {
            Channel.OPPO -> {
                if (BrandUtil.isOppoChannel()) {
                    block()
                }
            }

            Channel.VIVO -> {
                if (BrandUtil.isVivoChannel()) {
                    block()
                }
            }

            Channel.XIAOMI -> {
                if (BrandUtil.isXiaoMiChannel()) {
                    block()
                }
            }
        }
    }

    /**
     * 7天内付费
     */
    internal fun checkPayWithinSevendays(): Boolean {
        UserInfoUtils.getInstance()?.userInfoEntity?.userInfo?.create_time?.let { timeStr ->
            format.parse(timeStr)?.let {
                val calendar = Calendar.getInstance()
                calendar.time = it

                val dist = System.currentTimeMillis() - calendar.timeInMillis
                val oneDay = 24 * 60 * 60 * 1000
                if (dist < oneDay * 7) {
                    LogUtils.d("payAction: 7天内付费")
                    return true
                }
            }
        }
        return false
    }

    /**
     * 次日留存
     */
    internal fun checkSeconddayRetention(): Boolean {
        val application = BaseApplication.getApplication()
        val packageManager = application.packageManager
        val packageInfo = packageManager.getPackageInfo(application.packageName, 0)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val today = LocalDate.now()
            val firstInstallTime =
                LocalDate.ofEpochDay(Duration.ofMillis(packageInfo.firstInstallTime).toDays())
            val gap = ChronoUnit.DAYS.between(firstInstallTime, today)
            if (gap == 1L) {
                return true
            }
        }
        return false
    }

    /**
     * 判断是否首次安装
     *
     * @param instance
     * @return
     */
    internal fun checkIsFirstInstall(application: Application): Boolean {
        val packageManager = application.packageManager
        val packageInfo = packageManager.getPackageInfo(application.packageName, 0)
        return packageInfo.firstInstallTime == packageInfo.lastUpdateTime && MmkvUtils.get(FIRST_LAUNCH, true)
    }

    /**
     * 一键登录、微信登录都是后台登录时自动注册，无法判断是不是新注册用户
     * 根据create_time判断是不是新注册用户
     * 注册完3分钟内算新注册用户
     * @return
     */
    @Deprecated(message = "已弃用，登录时都传数据到后台，由后台处理是不是新注册用户", replaceWith = ReplaceWith("false"))
    fun checkIsRegister(): Boolean {
//        UserInfoUtils.getInstance().userInfoEntity?.userInfo?.create_time?.let { timeStr ->
//            format.parse(timeStr)?.let {
//                val calendar = Calendar.getInstance()
//                calendar.time = it
//
//                val dist = System.currentTimeMillis() - calendar.timeInMillis
//
//                val threeMinute = 3 * 60 * 1000
//                if (dist < threeMinute) {
//                    return true
//                }
//            }
//        }
        return false
    }

    /**
     * 判断是不是平板
     * @param context
     * @return
     */
    internal fun isPad(context: Context): Boolean {
        val dm = context.resources.displayMetrics
        val x = (dm.widthPixels / dm.xdpi).toDouble().pow(2.0)
        val y = (dm.heightPixels / dm.ydpi).toDouble().pow(2.0)
        val screenInches = sqrt(x + y)
        return DeviceUtils.isTablet() || screenInches >= 7.0
    }

    /**
     * 获取OAID
     * 需要放在子线程
     * @param application
     */
    private fun initOaid(application: Application) {
        if (oaid.isNullOrEmpty()) {
//            oaid = ba.b(application)
        }
    }

    /**
     * 上传数据到公司服务器
     * @param block
     */
    internal suspend fun Application.uploadActiveData(channel: Channel, block: suspend () -> String) {
        runCatching {
            initOaid(this)
            val str = "00000000-0000-0000-0000-000000000000"
            if (oaid.isNullOrEmpty() || oaid == str) {
                LogUtils.d("uploadActiveData: oaid为空")
                return
            }

            val uploadData = block()
            when (channel) {
                Channel.OPPO -> {
                    LogUtils.d("需要上传的OPPO数据: $uploadData")
                    if (isPad(this)) {
                        LogUtils.d("uploadActiveData: 平板设备")
                        return
                    }

                    if (oaid!!.startsWith("A")) {
                        LogUtils.d("uploadActiveData: oaid以A开头")
                        return
                    }

                    val result = uploadService.uploadOppoDataToService(uploadData.toRequestBody())
                    LogUtils.d("oppo归因上传结果: $result")
                }

                Channel.VIVO -> {
                    LogUtils.d("需要上传的VIVO数据: $uploadData")
                    val result = uploadService.uploadVivoDataToService(uploadData.toRequestBody())
                    LogUtils.d("vivo归因上传结果: $result")
                }

                Channel.XIAOMI -> {
                    LogUtils.d("uploadActiveData: 上传的参数: $uploadData")
                    val result2 = uploadService.uploadDataToSelfService(uploadData.toRequestBody())
                    LogUtils.d("xiaomi归因上传结果: $result2")
                }
            }
        }
    }

    // 自归因,增加补充接口userMonitor
    internal suspend fun Application.uploadMonitorData(block: suspend () -> String) {
        runCatching {
            initOaid(this)
            val str = "00000000-0000-0000-0000-000000000000"
            if (oaid.isNullOrEmpty() || oaid == str) {
                LogUtils.d("uploadActiveData: oaid为空")
                return
            }

            if (BrandUtil.isOppo()) {
                if (isPad(this)) {
                    LogUtils.d("uploadActiveData: 平板设备")
                    return
                }
                if (oaid!!.startsWith("A")) {
                    LogUtils.d("uploadActiveData: oaid以A开头")
                    return
                }
                LogUtils.d("oppo监测归因参数: ${block()}")
                val result = uploadService.userMonitorOppo(block().toRequestBody())
                LogUtils.d("oppo监测归因上传结果: $result")
            }
        }
    }

    private fun initUploadLocalService() {
        val logInterceptor = HttpLoggingInterceptor(LoggingInterceptor())
        logInterceptor.level = HttpLoggingInterceptor.Level.BODY
        val builder = OkHttpClient.Builder()
        val okHttpClient = builder
            .readTimeout(15000, TimeUnit.MILLISECONDS)
            .connectTimeout(15000, TimeUnit.MILLISECONDS)
            .addInterceptor(logInterceptor)
            .build()

        uploadService = Retrofit.Builder()
            .client(okHttpClient)
            .addConverterFactory(GsonConverterFactory.create())
            .baseUrl(baseUrl)
            .build().create(UploadService::class.java)
    }
}